#!/usr/bin/php
<?php
/*  ================================================================== *\
    (C) Copyright 2010 by Kenneth Downs

    This file is part of Triangulum 

    Triangulum is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    Triangulum is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Triangulum; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor,
    Boston, MA  02110-1301  USA
    or visit http://www.gnu.org/licenses/gpl.html
\*  ================================================================== */
/**
 *  This file executes a previously generated build script
 *  
 *  @author Kenneth Downs <kdowns@downsfam.net>
 *  @contributor Donald J Organ IV, <dorgan@donalorgan.com>
 *  @package Triangulum
 *
 
 
 #
 #  TO DO: Run "Checks" if required, unit
 #         testing maybe should be in here, contrive
 #         a database that will fail one each and pass
 #         one each of all of them.
 #
 #      1. PK/Unique changes, addition of new columns
 #      2. FK changes, when columns already exist
 #      3. NOT NULL, when values exist
 #      4. Type Changes
 #      5. Size Reductions
 #
 #
 #
 */
 
#  Very important environment setting
# 
error_reporting(E_ALL);
 
# First thing, identify current working directory, we will
# switch out of it and later back into it
#
$envCWD = getcwd();

# Next thing is to switch into the directory of this file
#
chdir(dirname(__FILE__));
echo "\n\nNow in directory ".getcwd();

# ...and invoke the main event
#
$triMain = new triMain;
$triMain->main($argc,$argv);

#  go back where we came from before exiting
#
chdir($envCWD);

return;

# --------------------------------------------------------------------------
#
#   class definition
#
# --------------------------------------------------------------------------
class triMain {
    # Parameters from command line
    private $argv = array();
    
    public function main($argc,$argv) {
        # Make sure parameters are ok
        echo "\n==================================================";
        echo "\ntriMain - The Triangulum Database ";
        echo "\n          Build/Upgrade Utility           ";
        echo "\n==================================================";
        echo "\n";
        echo "\nConfirming Parameters";
        if (!$this->mainParms($argc,$argv)) return $this->usage();
        echo "\nConfirming Parameters - OK\n";
        
        # Ensure we can connect and create database
        echo "\nConnecting to (or creating) database";
        if (!$this->runConnectCreate()) return false;
        echo "\nConnecting to (or creating) database - OK\n";
        
        # Now run triBuild
        echo "\nRunning Database script builder";
        if (!$this->runTriBuild()) return false;
        echo "\nRunning Database script builder - OK\n";
        
        # If we are still here, run the checks
        echo "\nRunning Checks that upgrade can proceed";
        if (!$this->runChecks()) return false;
        echo "\nRunning Checks that upgrade can proceed - OK\n";
        
        # Finally, run the build/upgrade itself
        echo "\nUpgrading Database";
        $this->runBuild();
        echo "\nUpgrading Database - OK\n";
        echo "DONE\n\n";
    }
    
    private function mainParms($argc,$argv) {
        # Always shift off the first argument, it is just the
        # name of this script
        array_shift($argv);
        
        # Make a list of allowed args, which happens to also be the
        # list of *required* parms, it is pretty nice and simple
        # that way
        #
        $args = array('yaml','db-host','db-name','db-user','db-passwd');
        
        # Hardcoded postgres
        $this->argv['platform'] = 'postgres';

        $parmName = '';
        $parmValue= '';
        foreach($argv as $arg) {
            $arga = explode("=",$arg);
            if(count($arga)<>2) return false;
            
            $parmName = strtolower($arga[0]);
            while(substr($parmName,0,1)=='-') $parmName = substr($parmName,1);
            $parmValue= $arga[1];
            $parmidx  = array_search($parmName,$args);
            if($parmidx===false) {
                return false;
            }
            unset($args[$parmidx]);
            
            $this->argv[$parmName] = $parmValue;
        }
        
        # If there are any left over, no good
        if(count($args)>0) return false;
        
        # If we did not return false on any errors, must be ok
        return true;
    }
    
    private function usage() {
        ob_start();
        ?>
=============================================================
triMain.php 
=============================================================
THIS PROGRAM WILL BUILD OR UPGRADE YOUR DATABASE 
If you just want to process the dictionary and examine
the reports, use 'triBuild.php'

USAGE:

$ triMain.php parm=value parm=value

All parameters are required, the parameters are:

yaml:      /path/to/yourfile.dd.yaml
db-host:   hostname or ip # of database server
db-name:   database to upgrade
db-user:   superuser, must have ownership priveleges
db-passwd: password for super-user, (is not echoed to any output)
        <?php
        $text = ob_get_clean();
        echo $text."\n";
    }  
    
    private function runConnectCreate() {
        # First connect to master database
        $connString = $this->connString('postgres');
        $dbConn = @pg_connect($connString);
        if(!$dbConn) {
            echo "\n\n";
            echo "** Could not connect to postgres database\n";
            echo "** on server.  Cannot proceed.\n";
            return false;
        }
        
        $sql="select count(*) as theCount from pg_database
               where datname = '".$this->argv['db-name']."'";
        $dbResult = pg_query($sql);
        $dbRow    = pg_fetch_row($dbResult);
        if($dbRow[0]==1) {
            echo "\n -> Database {$this->argv['db-name']} exists";
        }
        else {
            echo "\n -> Database {$this->argv['db-name']} does not exist, creating";
            pg_query("Create database ".$this->argv['db-name']);
        }
        return true;    
    }
    
    private function runTriBuild() {
        # Get the base directory.  Make the debug 
        # directory if it is not there, and clear out
        # the errors count file if it is there
        $runDir = dirname($this->argv['yaml']);
        if(substr($runDir,0,2)=='./') $runDir = substr($runDir,2);
        $runDir = realpath($runDir);
        #$debug = $runDir."debug";
        #echo "\n\nThe debug dir is $debug\n\n";
        #if(!is_dir($debug)) {
        #    mkdir($debug);
        #}
        if(file_exists($runDir."debug/errors.count.txt")) {
            unlink($runDir."debug/errors.count.txt");
        }
        
        # Build the parm string and run it
        $parmString = '';
        foreach($this->argv as $name=>$value) {
            $parmString.="--$name=$value ";
        }
        $execString = "php triBuild.php $parmString";
        `$execString`;
        
        # Now check out the errors
        $errorCount = file_get_contents($runDir."/debug/errors.count.txt");
        if($errorCount>0) {
            return false;
        }
        
        # No early return false, so everything must be ok
        return true;
    }
    
    private function runChecks() {
        $retval = true;
        $runDir = dirname($this->argv['yaml']);
        $checks = unserialize(file_get_contents($runDir."/debug/checks.serialize"));
        $count  = count($checks);
        if($count==0) {
            echo "\n ->no checks to run, proceeding directly to upgrade";
        }
        else {
            $connString = $this->connString();
            $dbConn = pg_connect($connString);
            foreach($checks as $idx=> $details) {
                echo "\n -> ".($idx+1)." of $count: ".$details['desc'];
                $dbResult = pg_query($dbConn,$details['sql']);
                $dbRow    = pg_fetch_row($dbResult);
                if($dbRow[0]==0) {
                    echo "\n   ** PASSED **";
                }                
                else {
                    echo "\n  ** FAIL ** ";
                    echo "\n  ".$details['err'];
                    $retval = false;
                }
            }
        }
        if(!$retval) echo "\n\n";
        return $retval;
    }
    
    private function runBuild() {
        # Make a connection
        $connString = $this->connString();
        $dbConn = pg_connect($connString);

        # Get the directory    
        $outDir = dirname($this->argv['yaml'])."/out/";
          
        # Get the commands
        $lines = explode(
            "-- COMMAND --"
           ,file_get_contents($outDir."build.".$this->argv['platform'].".sql")
        );
        $ok = 0;
        $todo=0;
        foreach($lines as $idx=>$oneline) {
            if(trim($oneline)=='') continue;
            $todo++;
            while(substr($oneline,-1)=="\n") 
                $oneline = rtrim($oneline,"\n");
            pg_query($dbConn,$oneline);
        }
    }
    
    private function connString($dbname='') {
        $dbname = $dbname=='' ? $this->argv['db-name'] : $dbname;
        return       
             "host="    .$this->argv['db-host']
            ." dbname="  .$dbname
            ." user="    .$this->argv['db-user']
            ." password=".$this->argv['db-passwd'];
    }
}
?>
